Skip to content

feat(usage): always-on per-query usage tracking#614

Merged
galshubeli merged 7 commits into
stagingfrom
feat/usage-tracking
Jun 25, 2026
Merged

feat(usage): always-on per-query usage tracking#614
galshubeli merged 7 commits into
stagingfrom
feat/usage-tracking

Conversation

@galshubeli

@galshubeli galshubeli commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Why

While analyzing production usage we found that 235 of 240 users showed zero recorded queries — not because they weren't using the product, but because QueryWeaver has no usage-tracking system. The only per-query record was a side effect of the optional LLM conversational-memory feature (api/memory/graphiti_tool.py), which is:

  • opt-in — gated by use_memory (default False for the SDK),
  • provider-gated — silently disabled unless the LLM provider is OpenAI/Azure,
  • lazy + fire-and-forget — the -memory graph only exists after a qualifying query, and failures are swallowed.

Consequently every recorded query in production was against the demo DB (DEMO_CRM) — not a single own-database query was ever tracked. Usage counts were unusable for measuring adoption.

What

Adds a dedicated, always-on, provider-agnostic usage-tracking layer that records every query, independent of the memory feature.

  • New api/core/usage_tracking.pyrecord_query_usage_background(...), a fire-and-forget recorder mirroring save_memory_background (background task, SDK task-sink support, errors logged-not-raised).
  • Storage on the central Organizations graph (alongside User/Identity/Token):
    • denormalized counters on the User node: query_count, success_count, error_count, last_active, first_query_at;
    • a per-query (:UsageEvent {graph_id, is_demo, success, timestamp}) linked (User)-[:PERFORMED]-> for time-series, per-DB and success-rate analytics (is_demo fixes the "all data is DEMO_CRM" blind spot).
  • Hook in run_query and run_confirmed at the completion point, outside the use_memory/provider gate, so it runs on every query. No route or signature changes.
  • Uses MATCH (not MERGE) on User, so an unknown email is a silent no-op rather than a phantom user.

Notes / scope

  • Forward-only — historical usage cannot be backfilled.
  • Out of scope (file separately): the memory-feature bugs (Episodic/Community/Saga never created, demo-only writes) and a read/admin API + frontend usage view.

Testing

  • New tests/test_usage_tracking.py (9 tests): write content for success/error, demo flag, ungated design (recorder has no use_memory/provider params), invalid user_id no-op, swallowed write failure. Marked @pytest.mark.unit.
  • Full unit suite green (25 passed, no regressions); pylint 10.00/10.
  • The exact Cypher was validated against a live FalkorDB engine (local dev DB): counters increment correctly, UsageEvent nodes are created, and an unknown email is a confirmed no-op (no phantom user). Production was not written to.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added always-on, per-query usage tracking that records query activity and per-query events.
    • Updated streaming pipelines to record usage when a final result is produced and to capture failures during streaming.
    • Made the central organizations/user-management graph name configurable (defaults to Organizations).
  • Bug Fixes
    • Skip usage tracking when the user identifier is missing or malformed; tracking won’t block responses.
    • Swallow usage write errors and log them instead of propagating exceptions.
  • Tests
    • Added unit tests covering decoding, background scheduling, and write-failure behavior for usage tracking.

Add a dedicated, provider-agnostic usage-tracking layer that records every
query onto the central Organizations graph, independent of the optional
LLM conversational-memory feature.

Background: the only pre-existing per-query record was a side effect of the
opt-in `use_memory` feature, which is also gated to OpenAI/Azure providers and
lazily created. As a result the vast majority of users had no recorded query
activity, and every recorded query was against the demo DB — usage counts were
unusable for measuring adoption.

This change:
- Adds api/core/usage_tracking.py with record_query_usage_background(), a
  fire-and-forget recorder mirroring save_memory_background (background task,
  task-sink support for the SDK, errors logged-not-raised).
- Maintains denormalized counters on the User node (query_count/success_count/
  error_count/last_active/first_query_at) plus a per-query (:UsageEvent) node
  linked (User)-[:PERFORMED]-> for time-series/per-DB/success-rate analytics.
- Hooks the recorder into run_query and run_confirmed at the completion point,
  OUTSIDE the use_memory/provider gate, so it runs on every query.
- Uses MATCH (not MERGE) on User so an unknown email is a silent no-op rather
  than creating a phantom user from the query path.

Forward-only: historical usage cannot be backfilled.

Tests: tests/test_usage_tracking.py (write content, demo flag, ungated design,
invalid user_id no-op, swallowed write failure). Cypher validated against a
live FalkorDB engine.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@overcut-ai

overcut-ai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Completed Working on "Code Review"

✅ Review publishing completed successfully. Posted comments from all chunks and submitted final review: COMMENT with 1 total comment across 1 file.

✅ Workflow completed successfully.


👉 View complete log

@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6db37333-a8c4-4947-9ac3-29043d4a47e0

📥 Commits

Reviewing files that changed from the base of the PR and between e47e580 and b4bd4df.

📒 Files selected for processing (3)
  • api/routes/graphs.py
  • api/routes/usage_tracking.py
  • tests/test_usage_tracking.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • api/routes/graphs.py
  • tests/test_usage_tracking.py
  • api/routes/usage_tracking.py

📝 Walkthrough

Walkthrough

Adds a configurable Organizations graph name, routes auth and token queries through it, records per-query usage in a background task, wires that tracking into streaming query flows, and adds unit tests.

Changes

Per-query usage tracking

Layer / File(s) Summary
Organizations graph config
api/config.py, .env.example, api/auth/user_management.py, api/routes/auth.py, api/routes/tokens.py
Defines ORGANIZATIONS_GRAPH from an environment variable with default "Organizations", documents it in .env.example, and replaces hardcoded "Organizations" graph name strings in auth, token, and user-management routes.
Usage tracking module
api/routes/usage_tracking.py
Defines _RECORD_USAGE_CYPHER to match a User by email and append a UsageEvent node, implements _decode_email for base64-with-@ validation, _write_usage to execute the Cypher against the Organizations graph, and record_query_usage_background to schedule the write as an asyncio background task with logged, swallowed failures.
graphs.py pipeline wiring
api/routes/graphs.py
Extends _serialize_pipeline to accept user_id and namespaced, capture the _Final result, and call record_query_usage_background when no confirmation is needed. Updates query_graph and confirm_destructive_operation to compute namespaced and forward both arguments into the serializer, and records failed streaming attempts with success=False.
Usage tracking tests
tests/test_usage_tracking.py
Covers _decode_email for valid and invalid inputs; covers record_query_usage_background for success/failure persistence, demo graph detection, invalid user ID short-circuit, swallowed write exceptions, and a design-contract assertion on the public function signature.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hop, hop, the graph name’s in a spell,
Background carrots track the queries well.
If one task tumbles, the burrow stays bright,
Logs wink softly in the evening light.
Unit-test paws tap, “all’s tidy and true,”
Then off I bound with a usage-trail view.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change: always-on per-query usage tracking.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/usage-tracking

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread api/core/usage_tracking.py Fixed

@overcut-ai overcut-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

Findings by severity:

  • MAJOR: 1
  • BLOCKER/CRITICAL/MINOR/SUGGESTION/PRAISE: 0

Affected files:

  • api/core/text2sql.py

Key theme:

  • Usage tracking coverage is incomplete on early-exit paths, which can undercount real query activity and conflict with the always-on tracking goal.

Actionable next steps:

  1. Ensure usage recording runs on all terminal paths in run_query and run_confirmed (including early returns and exceptions), ideally via a single finally-style completion hook.
  2. Add/extend tests to cover early-exit/error paths to verify exactly-once usage recording behavior.

Comment thread api/core/text2sql.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
api/core/usage_tracking.py (1)

40-53: 🚀 Performance & Scalability | 🔵 Trivial

Plan for unbounded UsageEvent growth.

Every query CREATEs a new (:UsageEvent) node on the shared Organizations graph with no retention bound. Over time this graph grows without limit, and time-series/per-DB analytics queries will scan ever-larger node sets. Consider an index on UsageEvent(timestamp) (and/or graph_id) for read efficiency, plus a retention/rollup strategy.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/core/usage_tracking.py` around lines 40 - 53, The `record_usage` Cypher
in `_RECORD_USAGE_CYPHER` creates an unbounded `UsageEvent` node for every
query, so add a retention or rollup strategy to prevent indefinite growth while
keeping analytics usable. Update the usage-tracking flow around `UsageEvent`
creation to either prune older events, aggregate them into summary records, or
both, and add indexes on `UsageEvent.timestamp` and/or `graph_id` to keep reads
efficient. Keep the `MATCH (u:User ...)` update behavior intact while making the
event-storage path bounded.
tests/test_usage_tracking.py (1)

143-150: 📐 Maintainability & Code Quality | 🔵 Trivial

Consider a test for the no-sink path.

All TestRecordQueryUsage cases pass an explicit task_sink, so the sink is None branch (the one used by the server path via background_tasks_var) is never exercised. A test covering the no-sink scheduling path would guard against the task-GC concern raised in usage_tracking.py.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_usage_tracking.py` around lines 143 - 150, Add a test that
exercises the no-sink scheduling path in the usage tracking flow, since all
current TestRecordQueryUsage cases pass an explicit task_sink. Cover the branch
where record_query_usage_background is invoked with sink/task_sink absent and
the server-style background_tasks_var path is used, and assert the scheduled
task still runs or is retained correctly. Use the existing TestRecordQueryUsage
or TestUngatedDesign setup and reference record_query_usage_background and
background_tasks_var to place the new case alongside the current usage-tracking
tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/core/text2sql.py`:
- Around line 612-616: The usage tracking call in text2sql is currently placed
too late, so early-return paths like off-topic, non-translatable, demo-block,
and confirmation exits bypass it and are never counted. Move
record_query_usage_background(...) earlier in the query flow in the text2sql
handling logic so it runs before any of those returns, while keeping its
existing success flag and db arguments unchanged.

In `@api/core/usage_tracking.py`:
- Around line 86-89: The usage_event INFO log in usage_tracking.py is emitting
user-derived email and graph_id values without sanitization, which can allow log
forging via CR/LF. Update the logging path around the usage_event call to
neutralize or escape these fields before passing them to logging.info, and
consider reducing or removing the email PII from this high-volume INFO log if it
is not required. Use the usage_event logging statement as the place to apply the
fix.

---

Nitpick comments:
In `@api/core/usage_tracking.py`:
- Around line 40-53: The `record_usage` Cypher in `_RECORD_USAGE_CYPHER` creates
an unbounded `UsageEvent` node for every query, so add a retention or rollup
strategy to prevent indefinite growth while keeping analytics usable. Update the
usage-tracking flow around `UsageEvent` creation to either prune older events,
aggregate them into summary records, or both, and add indexes on
`UsageEvent.timestamp` and/or `graph_id` to keep reads efficient. Keep the
`MATCH (u:User ...)` update behavior intact while making the event-storage path
bounded.

In `@tests/test_usage_tracking.py`:
- Around line 143-150: Add a test that exercises the no-sink scheduling path in
the usage tracking flow, since all current TestRecordQueryUsage cases pass an
explicit task_sink. Cover the branch where record_query_usage_background is
invoked with sink/task_sink absent and the server-style background_tasks_var
path is used, and assert the scheduled task still runs or is retained correctly.
Use the existing TestRecordQueryUsage or TestUngatedDesign setup and reference
record_query_usage_background and background_tasks_var to place the new case
alongside the current usage-tracking tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0e4abbeb-6450-4184-9a14-ac8c450e348e

📥 Commits

Reviewing files that changed from the base of the PR and between b8e6602 and 972888d.

📒 Files selected for processing (3)
  • api/core/text2sql.py
  • api/core/usage_tracking.py
  • tests/test_usage_tracking.py

Comment thread api/core/text2sql.py Outdated
Comment thread api/routes/usage_tracking.py
@railway-app railway-app Bot temporarily deployed to queryweaver / QueryWeaver-pr-614 June 24, 2026 11:50 Destroyed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an always-on, provider-agnostic usage tracking mechanism to record per-query activity in the central Organizations graph, independent of the optional conversational-memory feature, to enable reliable adoption/usage analytics.

Changes:

  • Introduces api/core/usage_tracking.py with a fire-and-forget recorder that updates denormalized counters on User and appends UsageEvent nodes.
  • Hooks usage recording into both run_query and run_confirmed completion points in api/core/text2sql.py.
  • Adds unit tests validating decoding, write parameters, demo-flagging, failure swallowing, and ungated design.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
api/core/usage_tracking.py New background usage recorder + Cypher write into Organizations graph.
api/core/text2sql.py Integrates usage tracking calls into the query and confirmed-destructive flows.
tests/test_usage_tracking.py Adds unit tests for the new tracking module behavior and API shape.

Comment thread api/core/usage_tracking.py
Comment thread api/core/usage_tracking.py
Comment thread api/core/text2sql.py Outdated
Comment thread api/core/text2sql.py Outdated
@railway-app railway-app Bot temporarily deployed to queryweaver / QueryWeaver-pr-614 June 24, 2026 11:52 Destroyed
@railway-app

railway-app Bot commented Jun 24, 2026

Copy link
Copy Markdown

🚅 Deployed to the QueryWeaver-pr-614 environment in queryweaver

Service Status Web Updated (UTC)
QueryWeaver ✅ Success (View Logs) Web Jun 24, 2026 at 1:58 pm

- text2sql: record usage on every terminal path of run_query/run_confirmed
  (off-topic, not-translatable, demo-blocked, cancelled, no-loader), via a
  local _track_usage helper. The destructive-confirmation prompt is the
  deliberate exception — run_confirmed records that query's outcome, so
  tracking it twice would double-count.
- usage_tracking: omit email (PII) from the per-query log line and strip
  CR/LF from the user-influenced graph_id (CodeQL log-injection).
- usage_tracking: base64 decode with validate=True + email-shape check so a
  malformed user_id is skipped instead of triggering a phantom write.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@railway-app railway-app Bot temporarily deployed to queryweaver / QueryWeaver-pr-614 June 24, 2026 12:48 Destroyed
@galshubeli galshubeli requested a review from Copilot June 24, 2026 12:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread api/routes/usage_tracking.py
Two design fixes raised in review:

1. Single source of truth for the central graph name. Add
   config.ORGANIZATIONS_GRAPH (env var ORGANIZATIONS_GRAPH, default
   "Organizations") and use it everywhere the graph was hardcoded —
   auth/user_management, routes/auth, routes/tokens, and usage tracking.

2. Don't ship hosted-app telemetry in the PyPI SDK. Move usage_tracking
   from api/core (shipped) to api/routes (excluded from the wheel) and
   invoke it from the route layer (_serialize_pipeline) instead of inside
   run_query/run_confirmed in api/core/text2sql.py. The route records
   exactly once from the final QueryResult and skips the destructive-
   confirmation prompt (the /confirm call records that query). text2sql.py
   is back to its pristine, tracking-free state.

Verified: SDK wheel no longer contains usage_tracking and text2sql has no
tracking refs; unit suite 138 passed, pylint 10/10.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@railway-app railway-app Bot temporarily deployed to queryweaver / QueryWeaver-pr-614 June 24, 2026 13:21 Destroyed
@railway-app railway-app Bot temporarily deployed to queryweaver / QueryWeaver-pr-614 June 24, 2026 13:24 Destroyed
@galshubeli galshubeli requested a review from Copilot June 24, 2026 13:26

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
api/routes/auth.py (1)

137-174: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Initialize safe_email before the try.

If db.select_graph(ORGANIZATIONS_GRAPH) fails, the except block logs safe_email before it has been assigned, so the original error gets replaced by UnboundLocalError.

Suggested fix
 async def _set_mail_hash(email: str, password_hash: str) -> bool:
     """Set email hash for the user in the database."""
+    safe_email = _sanitize_for_log(email)
     try:
         organizations_graph = db.select_graph(ORGANIZATIONS_GRAPH)
-
-        # Sanitize inputs for logging
-        safe_email = _sanitize_for_log(email)
 
         # Create new email identity and user
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/routes/auth.py` around lines 137 - 174, Initialize safe_email before
entering the try block in _set_mail_hash so it is always available in the except
path. The current logging in the exception handler references safe_email after
db.select_graph(ORGANIZATIONS_GRAPH) can fail, which can mask the original error
with an UnboundLocalError; move the _sanitize_for_log(email) assignment above
the try and keep the existing logging/HTTPException flow unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/config.py`:
- Around line 17-20: The ORGANIZATIONS_GRAPH config currently preserves an empty
string, which causes downstream db.select_graph(ORGANIZATIONS_GRAPH) calls to
use an invalid graph name. Update the configuration in config.py so the
Organizations default is used when the environment variable is missing or blank,
and keep the change localized to the ORGANIZATIONS_GRAPH constant and its
surrounding fallback logic.

In `@api/routes/graphs.py`:
- Around line 57-60: Early exceptions in the graph query flow can return before
the _Final sentinel is set, so usage tracking is skipped entirely. Update the
route-level error handling in graphs.py and the query handlers around
run_query() and run_confirmed() so record_query_usage_background is invoked for
any failed request, including pre-result failures like get_db_description()
awaits; use the existing user_id, namespaced, and success=False path even when
the exception is caught before final is produced.
- Line 37: The _serialize_pipeline helper is still missing explicit typing, so
update its signature to annotate gen as AsyncGenerator[dict | _Final, None],
user_id as str, namespaced as str, and declare the return type as
AsyncGenerator[str, None]. Make the change directly on _serialize_pipeline so it
matches the repository typing rule and keeps pylint satisfied.

---

Outside diff comments:
In `@api/routes/auth.py`:
- Around line 137-174: Initialize safe_email before entering the try block in
_set_mail_hash so it is always available in the except path. The current logging
in the exception handler references safe_email after
db.select_graph(ORGANIZATIONS_GRAPH) can fail, which can mask the original error
with an UnboundLocalError; move the _sanitize_for_log(email) assignment above
the try and keep the existing logging/HTTPException flow unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aa885f91-0cc5-41ce-9dd3-832feb5d8760

📥 Commits

Reviewing files that changed from the base of the PR and between c12dbcb and eed65d1.

📒 Files selected for processing (8)
  • .env.example
  • api/auth/user_management.py
  • api/config.py
  • api/routes/auth.py
  • api/routes/graphs.py
  • api/routes/tokens.py
  • api/routes/usage_tracking.py
  • tests/test_usage_tracking.py
✅ Files skipped from review due to trivial changes (1)
  • .env.example
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_usage_tracking.py

Comment thread api/config.py Outdated
Comment thread api/routes/graphs.py
Comment thread api/routes/graphs.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comment thread api/routes/graphs.py
Comment thread tests/test_usage_tracking.py Outdated
Comment thread api/routes/usage_tracking.py Outdated
…ack crashes

- usage_tracking: the per-query log line logged the namespaced graph_id
  ({base64(email)}_{db}); base64 email is reversible, so log a short SHA-256
  hash instead — keeps identity out of logs and neutralizes log-injection.
- config: ORGANIZATIONS_GRAPH falls back to "Organizations" when the env var
  is empty (not just unset), so a blank value can't target an empty graph.
- routes/graphs: record success=False when run_query/run_confirmed raise
  before the _Final sentinel (e.g. get_db_description), so pipeline crashes
  are still counted instead of silently bypassing tracking.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@railway-app railway-app Bot temporarily deployed to queryweaver / QueryWeaver-pr-614 June 24, 2026 13:36 Destroyed
Address the latest review pass:
- routes/graphs: success = is_valid AND no error. error_message-None alone
  counted off-topic / not-SQL-translatable results (is_valid=False, no error)
  as successes, inflating success_count.
- tests: assert against usage_tracking.ORGANIZATIONS_GRAPH instead of the
  hardcoded "Organizations" so the suite passes when the env var is set.
- usage_tracking: reword the task_sink docstring — it no longer ships in the
  SDK, so drop the QueryWeaver.close() reference for a generic description.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@railway-app railway-app Bot temporarily deployed to queryweaver / QueryWeaver-pr-614 June 24, 2026 13:57 Destroyed
@galshubeli galshubeli requested a review from DvirDukhan June 24, 2026 14:49
@galshubeli galshubeli merged commit 37c2013 into staging Jun 25, 2026
14 checks passed
@galshubeli galshubeli deleted the feat/usage-tracking branch June 25, 2026 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants